<?php
/**
 * Created by PhpStorm.
 * User: 王崇全
 * Date: 2018/4/23
 * Time: 11:51
 */

namespace app\common\model;

use think\Image;

/**
 * 图片处理类
 * @author  王崇全
 * @date    2018/12/21 16:36
 * @package app\common\model
 */
class Img
{

    const IMG_PATH  = DS.'file'.DS;    //图片路径
    const DIR_FILES = ROOT_PATH.'public'.self::IMG_PATH; // 图片完整路径
    const SIZE      = (1024 * 1024) * 2; //文件上传最大值

    //头像缩略图尺寸
    const DEFN_L_HP = 30;
    const DEFN_M_HP = 48;
    const DEFN_H_HP = 96;

    //图片缩略图尺寸
    const DEFN_L = 96;
    const DEFN_M = 200;
    const DEFN_H = 400;

    /**
     * 图片上传
     * @author 王崇全
     * @date   2018/12/21 17:24
     * @return string 相对于网站根目录的路径
     * @throws \Exception
     */
    public static function upload()
    {
        $file = request()->file();

        if (!$file) {
            throw new \Exception("未检测到上传的文件");
        }

        //取第一个上传的文件
        $file = reset($file);
        if (!$file) {
            throw new \Exception("未检测到上传的文件");
        }

        if (!file_exists(self::DIR_FILES)) {
            mkdir(self::DIR_FILES, 0755, true);
        }

        $info = $file->validate([
            'size' => self::SIZE,
            'ext'  => 'jpg,jpeg,png,gif,ico',
        ])
                     ->rule("date")
                     ->move(self::DIR_FILES);
        if (!$info) {
            throw new \Exception($file->getError());
        }

        return self::IMG_PATH.$info->getSaveName();
    }

    /**
     * 返回图片的base64编码
     * @author 王崇全
     * @param string $file     文件的完整路径
     * @param bool   $compress 是否压缩尺寸
     * @return string
     * @throws
     */
    public static function RtnBase64(string $file, bool $compress = true)
    {
        if (!is_file($file)) {
            throw new \Exception("文件不存在或不是图片");
        }

        $bsae64 = 'data:'.mime_content_type($file).';base64,'.base64_encode(file_get_contents($file));
        $size   = strlen($bsae64);

        $sizeTo=1024 * 600 - 2;

        //压缩数据，使其小于32K (为了兼容IE8以及提高性能)
        if (($size >=$sizeTo ) && $compress)//&& IE8)
        {
            //临时文件
            $tmpPath = TEMP_PATH."my/";
            if (!is_dir($tmpPath) && !mkdir($tmpPath, 0755, true)) {
                throw new \Exception("临时目录创建失败");
            }
            $tmpFile = $tmpPath.uniqid();
            copy($file, $tmpFile);

            $width = 750;
            while (true) {
                if ($size < $sizeTo || $width < 50) {
                    break;
                }

                //压缩图片
                self::Resize($tmpFile, $width, $width);

                $bsae64 = 'data:'.mime_content_type($file).';base64,'.base64_encode(file_get_contents($tmpFile));
                $size   = strlen($bsae64);

                $width -= 50;
            }

            //删除临时文件
            @unlink($tmpFile);
        }

        return $bsae64;
    }

    /**
     * 创建缩略图 (详见下注释)
     * 生成的缩略图会存放在 "原路径+thumb/" 下 缩略图精度即缩略图的文件名
     * eg: ./img/picture 生成的缩略图可能是./img_thumb/200
     * @author 王崇全
     * @param string $file 文件的完整路径
     * @param string $type pic,图片;ps,头像
     * @return array 缩略图的路径
     * @throws
     */
    public static function ThumbCreate(string $file, string $type = "pic")
    {
        if (!is_file($file)) {
            throw new \Exception("文件错误");
        }

        $image = Image::open($file);

        $pathInfo = pathinfo($file);
        $dirName  = $pathInfo["dirname"].DIRECTORY_SEPARATOR.$pathInfo["filename"]."_thumb".DIRECTORY_SEPARATOR;
        if (!is_dir($dirName) && !mkdir($dirName, 0755, true)) {
            throw new \Exception("存放图片缩略图的路径创建失败");
        }

        $data = [];
        if ($type === "pic") {
            $image->thumb(self::DEFN_H, self::DEFN_H)
                  ->save($dirName.self::DEFN_H);
            $data[self::DEFN_H] = $dirName.self::DEFN_H;

            $image->thumb(self::DEFN_M, self::DEFN_M)
                  ->save($dirName.self::DEFN_M);
            $data[self::DEFN_M] = $dirName.self::DEFN_M;

            $image->thumb(self::DEFN_L, self::DEFN_L)
                  ->save($dirName.self::DEFN_L);
            $data[self::DEFN_L] = $dirName.self::DEFN_L;
        } elseif ($type === "ps") {
            $image->thumb(self::DEFN_H_HP, self::DEFN_H_HP)
                  ->save($dirName.self::DEFN_H_HP);
            $data[self::DEFN_H_HP] = $dirName.self::DEFN_H_HP;

            $image->thumb(self::DEFN_M_HP, self::DEFN_M_HP)
                  ->save($dirName.self::DEFN_M_HP);
            $data[self::DEFN_M_HP] = $dirName.self::DEFN_M_HP;

            $image->thumb(self::DEFN_L_HP, self::DEFN_L_HP)
                  ->save($dirName.self::DEFN_L_HP);
            $data[self::DEFN_L_HP] = $dirName.self::DEFN_L_HP;
        }

        return $data;
    }

    /**
     * 图像裁剪(不影响原图,详见下注释)
     * 剪切后的图片会放在 "原路径+crop/$width."_".$height."_".$left."_".$top" 下
     * eg: ./img/picture 的裁剪图片就是./img_crop/100_100_20_30
     * @author 王崇全
     * @param string $file   文件的完整路径
     * @param int    $width  宽
     * @param int    $height 高
     * @param int    $left   起始位置右移(像素)
     * @param int    $top    起始位置下移(像素)
     * @return string 裁剪的图片的完整路径
     * @throws
     */
    public static function ImgCrop(string $file, int $width, int $height, int $left = 0, int $top = 0)
    {
        $image    = Image::open($file);
        $pathInfo = pathinfo($file);
        $dirName  = $pathInfo["dirname"].DIRECTORY_SEPARATOR.$pathInfo["filename"]."_crop".DIRECTORY_SEPARATOR;
        if (!is_dir($dirName) && !mkdir($dirName, 0755, true)) {
            throw new \Exception("存放裁剪后的图片的路径创建失败");
        }

        $fileName = $width."_".$height."_".$left."_".$top;

        $image->crop($width, $height, $left, $top)
              ->save($dirName.$fileName);

        return $dirName.$fileName;
    }

    /**
     * 直接向浏览器输出图片
     * @author 王崇全
     * @param string $file 文件的完整路径
     * @return void
     * @throws
     */
    public static function RtnPic(string $file)
    {
        $info = getimagesize($file); //获取mime信息
        $fp   = fopen($file, "rb"); //二进制方式打开文件
        if (!$info || !$fp) {
            throw new \Exception("文件不存在或不是图片");
        }
        ob_end_clean();
        header("Content-type: {$info['mime']}");
        fpassthru($fp); // 输出至浏览器
        exit;
    }


    /**
     * 调整图片尺寸或生成缩略图(影响原图)
     * @param string $Image
     * @param int    $Dw   调整时最大宽度;缩略图时的绝对宽度
     * @param int    $Dh   调整时最大高度;缩略图时的绝对高度
     * @param int    $type 1,调整尺寸; 2,生成缩略图
     * @return void
     * @throws
     */
    protected static function Resize(string $Image, int $Dw = 450, int $Dh = 450, int $type = 1)
    {
        IF (!File_Exists($Image)) {
            throw new \Exception("文件不存在或不是图片");
        }
        //如果需要生成缩略图,则将原图拷贝一下重新给$Image赋值
        IF ($type != 1) {
            Copy($Image, Str_Replace(".", "_x.", $Image));
            $Image = Str_Replace(".", "_x.", $Image);
        }
        //取得文件的类型,根据不同的类型建立不同的对象
        $ImgInfo = GetImageSize($Image);
        Switch ($ImgInfo[2]) {
            Case 1:
                $Img = @ImageCreateFromGIF($Image);
                Break;
            Case 2:
                $Img = @ImageCreateFromJPEG($Image);
                Break;
            Case 3:
                $Img = @ImageCreateFromPNG($Image);
                Break;
        }
        //如果对象没有创建成功,则说明非图片文件
        IF (Empty($Img)) {
            //如果是生成缩略图的时候出错,则需要删掉已经复制的文件
            IF ($type != 1) {
                Unlink($Image);
            }

            throw new \Exception("文件不存在或不是图片");
        }
        //如果是执行调整尺寸操作则
        IF ($type == 1) {
            $w      = ImagesX($Img);
            $h      = ImagesY($Img);
            $width  = $w;
            $height = $h;
            IF ($width > $Dw) {
                $Par    = $Dw / $width;
                $width  = $Dw;
                $height = $height * $Par;
                IF ($height > $Dh) {
                    $Par    = $Dh / $height;
                    $height = $Dh;
                    $width  = $width * $Par;
                }
            } ElseIF ($height > $Dh) {
                $Par    = $Dh / $height;
                $height = $Dh;
                $width  = $width * $Par;
                IF ($width > $Dw) {
                    $Par    = $Dw / $width;
                    $width  = $Dw;
                    $height = $height * $Par;
                }
            }

            $nImg = ImageCreateTrueColor($width, $height);   //新建一个真彩色画布
            ImageCopyReSampled($nImg, $Img, 0, 0, 0, 0, $width, $height, $w, $h);//重采样拷贝部分图像并调整大小
            ImageJpeg($nImg, $Image);     //以JPEG格式将图像输出到浏览器或文件
            //如果是执行生成缩略图操作则
        } Else {
            $w    = ImagesX($Img);
            $h    = ImagesY($Img);
            $nImg = ImageCreateTrueColor($Dw, $Dh);
            IF ($h / $w > $Dh / $Dw) { //高比较大
                $height = $h * $Dw / $w;
                $IntNH  = $height - $Dh;
                ImageCopyReSampled($nImg, $Img, 0, -$IntNH / 1.8, 0, 0, $Dw, $height, $w, $h);
            } Else {   //宽比较大
                $width = $w * $Dh / $h;
                $IntNW = $width - $Dw;
                ImageCopyReSampled($nImg, $Img, -$IntNW / 1.8, 0, 0, 0, $width, $Dh, $w, $h);
            }
            ImageJpeg($nImg, $Image);
        }
    }

}